import { addReadyProduct, getReadyProduct } from '../core/ReadyProducts'
import { schedule } from '../core/Scheduler'
import SimulationSpeed from '../core/SimulationSpeed'
import { messageTransfer } from '../messaging/MessageTransfer'
import BaseStation from './BaseStation'
import Product from './Product'
import TrafficNetwork from '../../store/trafficNetwork/trafficNetwork'
import { simController } from '../simulation/SimController'
import { dispatcher } from '../core/Dispatcher'
import { currentTime } from '../core/SimulationClock'

class AGV extends BaseStation {
  speed: number
  capacity: number

  moveType: 'deliverGoods' | 'pickupGoods' = 'deliverGoods'
  agvStatus: 'stop' | 'move' = 'stop'

  mapping: { source: BaseStation; target: BaseStation }[] = [] //源-目标映射表

  needLoadGoodsEvents: { id: string; productId: string; x: number; y: number }[] = [] //存储需要装载货物的事件
  loadProduct: { sourceId: string; targetId: string[]; product: Product }[] = [] // 存储装载的货物

  targetPosition: { x: number; y: number } = { x: 0, y: 0 }
  currentAngle: number = 0 // 当前角度，单位是度

  limitationType: 'area' | 'road' = 'area'
  areaPoints: { x: number; y: number }[] = []
  roadPath: string = ''

  enableTraffic: boolean = false //是否启用交通网络
  currentPoint: string = ''
  targetPoint: string = ''
  planPath: string[] = [] // 路径规划结果

  targetEntityIndex: number = 0 // 目标实体索引

  constructor(
    id: string,
    name: string,
    x: number,
    y: number,
    width: number,
    height: number,
    speed: number,
    capacity: number
  ) {
    super(id, name, x, y, width, height)
    this.speed = speed
    this.capacity = capacity
  }

  set setNeedLoadGoodsEvents(data: { id: string; productId: string } | null) {
    if (data) {
      //先判断这个产品是否已经存在
      if (
        this.needLoadGoodsEvents.some(
          (event) => event.productId === data.productId && event.id === data.id
        )
      )
        return

      const { x, y } = this.getPositionById(data.id)
      this.needLoadGoodsEvents.push({ id: data.id, productId: data.productId, x, y })
      this.handleLoadGoodsEvent()
    } else {
      this.needLoadGoodsEvents.shift()
    }
  }

  public canReceiveProduct(id: string, product: Product): boolean {
    console.log(`[${currentTime}] 🚚 ${this.name} 接收产品 ${product.id}`)
    //接下来判断agv是否到达指定位置
    const { x: sourceX, y: sourceY } = this.getPositionById(id)
    //判断是否去启用了交通网络
    if (this.enableTraffic) {
      const entity = this.getEntityById(id)
      if (!entity) return false
      //根据entity的位置寻找最近的点位
      const nearestPoint = TrafficNetwork.getAdjacentPoints([entity.x, entity.y])
      if (!nearestPoint) return false
      //获取到目标点位
      const targetPosition = TrafficNetwork.getPositionById(nearestPoint.id)
      if (
        this.x === targetPosition[0] &&
        this.y === targetPosition[1] &&
        this.loadProduct.length <= this.capacity
      ) {
        return true
      } else {
        this.setNeedLoadGoodsEvents = { id, productId: product.id }
        return false
      }
    } else {
      //如果没有启用，则按正常的逻辑接收产品
      if (this.x === sourceX && this.y === sourceY && this.loadProduct.length <= this.capacity) {
        return true
      } else {
        this.setNeedLoadGoodsEvents = { id, productId: product.id }
        return false
      }
    }
  }

  //处理需要装载货物的事件
  private handleLoadGoodsEvent() {
    if (this.loadProduct.length >= this.capacity) return
    if (this.agvStatus !== 'stop') return

    if (this.needLoadGoodsEvents.length === 0) return
    const event = this.needLoadGoodsEvents[0]

    if (event) {
      this.setNeedLoadGoodsEvents = null

      // 先判断这个设备是否处于堵塞
      const sourceEntity = this.getEntityById(event.id)
      if (sourceEntity && dispatcher.isDeviceInBlockOrSpecial(sourceEntity)) {
        this.pretreatmentTargetPosition(sourceEntity, event.x, event.y)
        this.moveType = 'pickupGoods'

        if (this.agvStatus === 'stop') {
          this.agvStatus = 'move'
          this.moving()
        } else {
          this.moving()
        }
      } else {
        setTimeout(() => {
          this.handleLoadGoodsEvent()
        }, 100)
      }
    }
  }

  //接受就绪产品
  receiveReadyProduct(productId: string): void {
    const product = getReadyProduct(productId)
    if (!product) {
      return
    }
    product.setFrom(this.id)
    this.onProductReceived(product)
  }
  //接收货物
  protected onProductReceived(product: Product): void {
    if (this.loadProduct.length > this.capacity) {
      new Error('AGV装载货物已满')
    }
    const sourceEntity = this.getEntityByPosition()
    if (sourceEntity) {
      const targetIds = this.getTargetIdArrayBySourceId(sourceEntity.id)
      this.loadProduct.push({
        sourceId: sourceEntity.id,
        targetId: targetIds,
        product
      })

      messageTransfer('product', 'transport', {
        targetId: this.id,
        productId: product.id,
        x: this.x,
        y: this.y,
        angle: this.currentAngle,
        duration: 0
      })

      //下一步，判断是继续取货还是送货
      if (this.loadProduct.length < this.capacity && this.needLoadGoodsEvents.length > 0) {
        //继续取货
        this.handleLoadGoodsEvent()
      } else if (this.loadProduct.length > 0) {
        //送货
        this.startDeliverGoods()
      } else {
        console.log('AGV 无效指令')
      }
    } else {
      console.log('AGV 无法找到源节点')
    }
  }

  //开始送货的前置处理
  public startDeliverGoods() {
    if (this.loadProduct.length === 0) {
      this.agvStatus = 'stop'
      return
    }
    const { sourceId, product, targetId } = this.loadProduct[0]
    if (this.targetEntityIndex >= targetId.length) {
      this.targetEntityIndex = 0
    }
    const targetEntity = this.getEntityById(targetId[this.targetEntityIndex])
    this.targetEntityIndex++
    if (targetEntity && targetEntity.canReceiveProduct(sourceId, product)) {
      this.pretreatmentTargetPosition(targetEntity, targetEntity.x, targetEntity.y)
      this.moveType = 'deliverGoods'
      if (this.agvStatus === 'stop') {
        this.agvStatus = 'move'
        this.moving()
      } else {
        this.moving()
      }
    } else {
      schedule(1, () => this.startDeliverGoods(), 'agv find idle device')
    }
  }

  //在移动前预先处理目标位置和路径
  public pretreatmentTargetPosition(station: BaseStation, x: number, y: number) {
    // 如果agv已经绑定了交通网络，则使用交通网络进行移动
    if (this.enableTraffic) {
      //先找到目标点位
      const targetPointData = TrafficNetwork.getAdjacentPoints([station.x, station.y])
      if (!targetPointData) return
      this.targetPoint = targetPointData.id

      //寻找最优路径
      this.planPath = TrafficNetwork.getOptimalPath(this.currentPoint, this.targetPoint)
      if (this.planPath.length > 1) {
        //去掉第一个元素
        this.planPath.shift()
      }
      const nextPoint = this.planPath[0]
      const nextPointPosition = TrafficNetwork.getPositionById(nextPoint)
      if (nextPointPosition.length < 2) {
        new Error(`AGV 路径错误`)
      }
      this.targetPosition = { x: nextPointPosition[0], y: nextPointPosition[1] }
    } else {
      this.targetPosition = { x, y }
    }
  }

  //移动
  public moving() {
    if (this.agvStatus === 'stop') return
    if (simController.getStatus() !== 'running') return

    // 计算当前位置和目标位置的距离
    const dx = this.targetPosition.x - this.x
    const dy = this.targetPosition.y - this.y
    const distanceToTarget = Math.sqrt(dx * dx + dy * dy) // 直线距离

    // 计算目标角度（弧度转换为度数）
    const angleInRadians = Math.atan2(dy, dx) // 返回的是弧度
    const angleInDegrees = (angleInRadians * 180) / Math.PI // 将弧度转换为度数
    this.currentAngle = angleInDegrees // 更新AGV的当前角度

    // 如果AGV已经到达目标位置，则停止移动
    if (distanceToTarget === 0) {
      this.arriveDestination()
      return
    }

    // 计算在40ms（0.04s）内AGV能走的距离
    const timeInterval = 0.05
    const distancePerStep = this.speed * timeInterval * SimulationSpeed.getSpeed // 计算每50ms AGV可以移动的距离

    // 如果目标距离小于AGV在50ms内能走的距离，就直接到目标位置
    if (distanceToTarget <= distancePerStep) {
      this.x = this.targetPosition.x
      this.y = this.targetPosition.y
    } else {
      // 计算单位向量
      const moveRatio = distancePerStep / distanceToTarget
      this.x += dx * moveRatio
      this.y += dy * moveRatio
    }

    this.loadProduct.forEach((product) => {
      messageTransfer('product', 'transport', {
        targetId: this.id,
        productId: product.product.id,
        x: this.x,
        y: this.y,
        angle: this.currentAngle,
        duration: 0
      })
    })
    messageTransfer('agv', 'transport', {
      targetId: this.id,
      x: this.x,
      y: this.y,
      angle: this.currentAngle
    })
    setTimeout(() => {
      this.moving()
    }, 50)
  }

  //到达目的地
  public arriveDestination() {
    this.agvStatus = 'stop'

    /**
     * 到达目的地后，判断agv是否绑定了交通网络
     */
    if (this.enableTraffic) {
      if (this.currentPoint !== this.targetPoint && this.planPath.length > 1) {
        this.currentPoint = this.planPath[0]
        this.planPath.shift()
        const nextPoint = this.planPath[0]
        if (nextPoint) {
          const nextPointPosition = TrafficNetwork.getPositionById(nextPoint)
          this.targetPosition = { x: nextPointPosition[0], y: nextPointPosition[1] }
          //继续移动
          this.agvStatus = 'move'

          this.moving()
          return
        }
      }
    }

    if (this.moveType === 'pickupGoods') {
      const sourceEntity = this.getEntityByPosition()
      if (sourceEntity && dispatcher.isDeviceInBlockOrSpecial(sourceEntity)) {
        sourceEntity.tryDispatchCurrentProduct()
      }
    } else if (this.moveType === 'deliverGoods') {
      //派发货物
      this.tryDispatchCurrentProduct()
      /**
       * 如果还有货物则继续送货
       */
      if (this.loadProduct.length > 0) {
        this.startDeliverGoods()
      } else if (this.needLoadGoodsEvents.length > 0) {
        /**
         * 如果没有货物了，则检查是否有需要装载货物的事件
         */
        this.handleLoadGoodsEvent()
      }
    }
  }

  //尝试派发当前货物
  public tryDispatchCurrentProduct(): void {
    if (this.loadProduct.length === 0) return
    const productItem = this.loadProduct[0]
    const targetEntity = this.getEntityByPosition()
    if (targetEntity && targetEntity.canReceiveProduct(productItem.sourceId, productItem.product)) {
      const product = productItem.product
      this.loadProduct.shift()
      //当前产品添加到就绪产品队列中
      addReadyProduct(product)
      targetEntity.receiveReadyProduct(product.id)
    }
  }

  //根据sourceId获取到targetId数组
  private getTargetIdArrayBySourceId(sourceId: string): string[] {
    return this.mapping.filter((item) => item.source.id === sourceId).map((item) => item.target.id)
  }

  //根据id获取位置
  private getPositionById(id: string): { x: number; y: number } {
    for (const item of this.mapping) {
      if (item.source.id === id) {
        return { x: item.source.x, y: item.source.y }
      }

      if (item.target.id === id) {
        return { x: item.target.x, y: item.target.y }
      }
    }
    return { x: 0, y: 0 }
  }

  //根据id获取实体类
  private getEntityById(id: string): BaseStation | undefined {
    for (const item of this.mapping) {
      if (item.source.id === id) {
        return item.source
      } else if (item.target.id === id) {
        return item.target
      }
    }
    return undefined
  }

  //根据位置获取实体类
  private getEntityByPosition(): BaseStation | null {
    let station = null as BaseStation | null
    for (const item of this.mapping) {
      if (item.source.x === this.x && item.source.y === this.y) {
        station = item.source
        break
      } else if (item.target.x === this.x && item.target.y === this.y) {
        station = item.target
        break
      }
    }
    if (station) {
      return station
    }

    //如果没有找到，则改变策略，根据当前位置，寻找最近的实体类
    let minDistance = 100000
    for (const item of this.mapping) {
      const distance1 = Math.sqrt(
        Math.pow(this.x - item.source.x, 2) + Math.pow(this.y - item.source.y, 2)
      )
      if (distance1 < minDistance) {
        station = item.source
        minDistance = distance1
      }
      const distance2 = Math.sqrt(
        Math.pow(this.x - item.target.x, 2) + Math.pow(this.y - item.target.y, 2)
      )
      if (distance2 < minDistance) {
        station = item.target
        minDistance = distance2
      }
    }
    return station
  }

  //设置映射关系
  public setMapping(source: BaseStation, target: BaseStation) {
    this.mapping.push({ source, target })
  }

  //初始化交通点位信息
  public initTrafficPoint(id: string, distance: [number, number]) {
    this.currentPoint = id
    this.x = distance[0]
    this.y = distance[1]
    this.enableTraffic = true
    messageTransfer('agv', 'transport', {
      targetId: this.id,
      x: this.x,
      y: this.y,
      angle: 0
    })
  }
}

export default AGV
